home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / video / thrust-s.53 / thrust-s / thrust / src / thrust.c < prev    next >
C/C++ Source or Header  |  1995-11-06  |  18KB  |  928 lines

  1.  
  2. /* Written by Peter Ekberg, peda@lysator.liu.se */
  3.  
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <unistd.h>
  7. #include <string.h>
  8. #include <time.h>
  9. #include <ctype.h>
  10. #include <vgagl.h>
  11. #include <vga.h>
  12. #include <vgakeyboard.h>
  13. #include "thrust.h"
  14.  
  15. void *keyintadr;
  16. byte *bulletmap;
  17. Palette *palette;
  18. byte *blocks;
  19. byte *ship;
  20. byte *shieldship;
  21. byte *bana;
  22. byte *fuelmap;
  23. byte *loadmap;
  24. byte *shipstorage;
  25. byte *bulletstorage;
  26. byte *fragmentstorage;
  27. byte *fuelstorage;
  28. byte *loadstorage;
  29. byte *wirestorage;
  30.  
  31. word lenx; /* Banans max i x-len, anvΣnds senare till den aktuella */
  32. word leny; /* Banans max i y-len, storleken pσ banan. SΣtts i readbana() */
  33. word lenx3,leny3;
  34.              /* Status of game. */
  35. int alpha,deltaalpha;
  36. word loaded,loadcontact,loadpointshift;
  37. int loadpoint;
  38. int countdown;
  39. word crash,shoot,repetetive;
  40. word refueling;
  41. int speedx,speedy;
  42. long absspeed,oldabs;
  43. int kdir,dir;
  44. int shipdx,shipdy;
  45. int x,y;           /* ╓vre vΣnstra h÷rnet 8 enh. per pixel. */
  46. int pixx,pixy;           /* ╓vre vΣnstra h÷rnet i pixels.   */
  47. int pblockx,pblocky;    /* ╓vre vΣnstra h÷rnet i block. */
  48. int vx,vy;                /* Skeppets hastighet. */
  49. int bildx,bildy;     /* ╓vre vΣnstra h÷rnet av fuskbilden i pixels. */
  50. int bblockx,bblocky;    /* ╓vre vΣnstra h÷rnet av fuskbilden i block.  */
  51. int loadbx,loadby;       /* Lastens placering pσ banan i blocks. */
  52. int gravity;
  53. int score;
  54. byte shield;
  55. byte colorr, colorg, colorb;
  56.  
  57. #define checkfork(b,a) \
  58.   case b-1: \
  59.     if(easyrider==a || easyrider==a+1) \
  60.       easyrider=a+1; \
  61.     else \
  62.       easyrider=-1; \
  63.     break
  64.  
  65. int
  66. insideblock(blockx, blocky, pblockx, pblocky, sx, sy)
  67.      int blockx, blocky, pblockx, pblocky, sx, sy;
  68. {
  69.   return((blockx>=pblockx-sx) && (blockx<pblockx+BBILDX) &&
  70.      (blocky>=pblocky-sy) && (blocky<pblocky+BBILDY));
  71. }
  72.  
  73. int
  74. insidepixel(x, y, pixx, pixy, sx, sy)
  75.      int x, y, pixx, pixy, sx, sy;
  76. {
  77.   return((x>pixx-sx) && (x<pixx+PSCRX) &&
  78.      (y>pixy-sy) && (y<pixy+PSCRY));
  79. }
  80.  
  81. void
  82. updateborder(pblockx, pblocky, bblockx, bblocky, vx, vy)
  83.      int pblockx, pblocky, bblockx, bblocky;
  84.      int vx, vy;
  85. {
  86.   word k;
  87.  
  88.   if(vy>0)
  89.     for(k=0; k<BBILDX; k++)
  90.       putblock(bblockx+k, (bblocky+BBILDY-1)%BBILDY, blocks+
  91.            (*(bana+(pblockx+k)%lenx+((pblocky+BBILDY-1)%leny)*lenx)<<6));
  92.   else
  93.     for(k=0; k<BBILDX; k++)
  94.       putblock(bblockx+k, bblocky, blocks+
  95.            (*(bana+(pblockx+k)%lenx+(pblocky%leny)*lenx)<<6));
  96.   if(vx>0)
  97.     for(k=0; k<BBILDY; k++)
  98.       putblock(bblockx+BBILDX-1, (bblocky+k)%BBILDY, blocks+
  99.            (*(bana+(pblockx+BBILDX-1)%lenx+((pblocky+k)%leny)*lenx)<<6));
  100.   else
  101.     for(k=0; k<BBILDY; k++)
  102.       putblock(bblockx, (bblocky+k)%BBILDY, blocks+
  103.            (*(bana+pblockx%lenx+((pblocky+k)%leny)*lenx)<<6));
  104. }
  105.  
  106. void
  107. fade_in()
  108. {
  109.   int i;
  110.  
  111.   for(i=1; i<=64; i++)
  112.     fadepalette(0,255,palette,i,1);
  113. }
  114.  
  115. void
  116. fade_out()
  117. {
  118.   int i;
  119.  
  120.   for(i=64; i; i--)
  121.     fadepalette(0,255,palette,i,1);
  122.   gl_clearscreen(0);
  123.   vga_setpage(0);
  124.   usleep(500000L);
  125. }
  126.  
  127. void
  128. pause_message()
  129. {
  130.   char *str[] = {
  131.     "GAME PAUSED.",
  132.     "PRESS 'C' TO CONTINUE..." };
  133.  
  134.   chflag=1;
  135.   gcenter(80,str[0]);
  136.   gcenter(91,str[1]);
  137.   chflag=0;
  138. }
  139.  
  140. void
  141. escape_message()
  142. {
  143.   char *str[] = {
  144.     "ARE YOU SURE YOU WANT TO QUIT (Y/N)?" };
  145.  
  146.   chflag=1;
  147.   gcenter(85,str[0]);
  148.   chflag=0;
  149. }
  150.  
  151. enum {
  152.   pause_bit =1<<0,
  153.   escape_bit=1<<1,
  154.   right_bit =1<<2,
  155.   left_bit  =1<<3,
  156.   fire_bit  =1<<4,
  157.   pickup_bit=1<<5,
  158.   thrust_bit=1<<6,
  159.   quit_bit  =1<<7
  160. };
  161.  
  162. byte
  163. whatkeys()
  164. {
  165.   byte keybits=0;
  166. /* Use this to create a demo. */
  167. /*
  168.   static FILE *f=NULL;
  169.   if(f == NULL)
  170.     f=fopen("foobarfoo", "w");
  171. */
  172.   keyboard_update();
  173.  
  174.   if(keyboard_keypressed(SCANCODE_P))
  175.     keybits|=pause_bit;
  176.   else if(keyboard_keypressed(SCANCODE_ESCAPE) ||
  177.       keyboard_keypressed(SCANCODE_Q))
  178.     keybits|=escape_bit;
  179.   if(keyboard_keypressed(SCANCODE_S))
  180.     keybits|=right_bit;
  181.   if(keyboard_keypressed(SCANCODE_A))
  182.     keybits|=left_bit;
  183.   if(keyboard_keypressed(SCANCODE_ENTER))
  184.     keybits|=fire_bit;
  185.   if(keyboard_keypressed(SCANCODE_SPACE))
  186.     keybits|=pickup_bit;
  187.   if(keyboard_keypressed(SCANCODE_RIGHTCONTROL))
  188.     keybits|=thrust_bit;
  189. /*
  190.   fputc((keybits&escape_bit)?quit_bit:escape_bit, f);
  191. */
  192.   return(keybits);
  193. }
  194.  
  195. byte
  196. nextmove(int reset)
  197. {
  198.   static byte *p;
  199.   byte retbits=0;
  200.  
  201.   if(reset) {
  202.     keyboard_update();
  203.     p=&bin_demomoves[0];
  204.   }
  205.   else if(keyboard_update())
  206.     retbits=quit_bit;
  207.   else {
  208.     retbits=*(p++);
  209.     retbits&=~thrust_bit;
  210.     retbits|=*(p-!!(random()%30)) & thrust_bit;
  211.   }
  212.  
  213.   return(retbits);
  214. }
  215.  
  216. int
  217. game(int demo)
  218. {
  219.   byte actionbits=0;
  220.   int ax,ay,aradial,acircum;
  221.   word lives,endlevel;
  222.   word dying;
  223.   word alive;
  224.   word fuel;
  225.   int l;
  226.   word wrapers;
  227.   int level;
  228.   int round;
  229.   static char **levels[LEVELS] = { level1, level2, level3, level4 };
  230.   static char textstr[40];
  231.   int localscore;
  232.   options end;
  233.   int ch;
  234.   int lastlevel;
  235.   int easyrider=0;
  236.   int restartx=0, restarty=0;
  237.   restartpoint *restartxy;
  238.   int gravitymsg;
  239.   int teleport;
  240.  
  241.   if(demo)
  242.     nextmove(1);
  243.  
  244.   lives=3; /* 3 */
  245.   localscore=0;
  246.   score=0;
  247.   round=0; /* 0 */
  248.   level=0; /* 0 */
  249.   lastlevel=-1;
  250.   shield=0;
  251.   fuel=1000; /* 1000 */
  252.   gravitymsg=0;
  253.   teleport=0;
  254.  
  255.   while(level<LEVELS && lives>0 && fuel) {
  256.     endlevel=0;
  257.     wrapers=0;
  258.     dying=0;
  259.     alive=1;
  260.     
  261.     srandom(time(NULL));
  262.     if(level!=lastlevel || !spacestation) {
  263.       if(level==0 && lastlevel!=-1)
  264.     gravitymsg=1;
  265.       if(!readbana(levels[level])) {
  266.     printf("Illegal definition of level %d.\n", level+1);
  267.     return(1);
  268.       }
  269.       restartx=0;
  270.       restarty=0;
  271.       initgame(round, 1, 0, 0);
  272.     }
  273.     else
  274.       initgame(round, 0, restartx, restarty);
  275.  
  276.     initscreen();
  277.     putscr(pixx%PBILDX,pixy%PBILDY);
  278.     lastlevel=level;
  279.     
  280.     printgs(250,188,"FUEL");
  281.     sprintf(textstr,"LIVES: %d",lives);
  282.     printgs(20,192,textstr);
  283.     sprintf(textstr,"SCORE: %d",score);
  284.     printgs(20,184,textstr);
  285.     sprintf(textstr,"LEVEL %d", level+1);
  286.     gcenter(70, textstr);
  287.     if(gravitymsg)
  288.       gcenter(60, (round&1) ? "REVERSED GRAVITY": "NORMAL GRAVITY");
  289.     gravitymsg=0;
  290.     fade_in();
  291.     usleep(750000UL);
  292.     vga_waitretrace();
  293.     putscr(pixx%PBILDX,pixy%PBILDY);
  294.     while(!endlevel) {
  295.       actionbits=demo ? nextmove(0) : whatkeys();
  296.  
  297.       if(actionbits&quit_bit)
  298.     endlevel=1;
  299.  
  300.       if(actionbits&pause_bit) {
  301.     pause_message();
  302.     keyboard_close();
  303.     vga_unlockvc();
  304.     end=NOTHING;
  305.     while(vga_getkey());
  306.     while(end==NOTHING) {
  307.       ch=vga_getkey();
  308.       switch(tolower(ch)) {
  309.       case 'p':
  310.         easyrider=0;
  311.         break;
  312.       case 'M':
  313.         checkfork('m', 0);
  314.         checkfork('b', 1);
  315.         checkfork('z', 2);
  316.         checkfork('h', 3);
  317.         checkfork('s', 4);
  318.         checkfork('p', 5);
  319.         checkfork('v', 6);
  320.         checkfork('o', 7);
  321.         checkfork('e', 8);
  322.         break;
  323.       case 'c':
  324.       case 'q':
  325.       case 27:
  326.         end=PLAY;
  327.         break;
  328.       }
  329.       usleep(10000UL);
  330.     }
  331.     if(easyrider!=9)
  332.       easyrider=0;
  333.     vga_lockvc();
  334.     keyboard_init();
  335.       }
  336.       if(actionbits&escape_bit) {
  337.     escape_message();
  338.     keyboard_close();
  339.     vga_unlockvc();
  340.     end=NOTHING;
  341.     while(end==NOTHING) {
  342.       ch=vga_getkey();
  343.       switch(tolower(ch)) {
  344.       case 'y':
  345.         end=END;
  346.         endlevel=1;
  347.         level=LEVELS;
  348.         break;
  349.       case 'n':
  350.         end=PLAY;
  351.         break;
  352.       }
  353.       usleep(10000UL);
  354.     }
  355.     vga_lockvc();
  356.     keyboard_init();
  357.       }
  358.       if(alive && (actionbits&right_bit)) {
  359.     decr(kdir,0,96);
  360.     dir=kdir/3;
  361.       }
  362.       if(alive && (actionbits&left_bit)) {
  363.     incr(kdir,96,0);
  364.     dir=kdir/3;
  365.       }
  366.       if(alive && (actionbits&fire_bit)) {
  367.     if(!shoot) {
  368.       shoot=1;
  369.       newbullet(x+((160+shipdx)<<3)+(sinus[(dir+8)&31]>>2),
  370.             y+((88+shipdy)<<3)-(sinus[dir]>>2),
  371.             (speedx+(sinus[(dir+8)&31]<<5))>>8,
  372.             (speedy-(sinus[dir]<<5))>>8,
  373.             kdir/6,1);
  374.     }
  375.     else if(repetetive || easyrider)
  376.       shoot=0;
  377.       }
  378.       else
  379.     shoot=0;
  380.       refueling=0;
  381.       if(alive && (actionbits&pickup_bit)) {
  382.     if(fuel>0) {
  383.       if(shield++==3) {
  384. #ifndef DEBUG
  385.         if(!easyrider)
  386.           fuel--;
  387. #endif
  388.         shield=1;
  389.       }
  390.     }
  391.     else
  392.       shield=0;
  393.     l=closestfuel((pixx+shipdx+160)%lenx3,
  394.               (pixy+shipdy+88)%leny3);
  395.     if(l>=0)
  396.       if(resonablefuel((pixx+shipdx+160)%lenx3,
  397.                (pixy+shipdy+88)%leny3,l)) {
  398. #ifndef DEBUG
  399.         if(!easyrider)
  400.           fuel+=6;
  401. #endif
  402.         refueling=1;
  403.         things[l].alive--;
  404.         if(things[l].alive==1)
  405.           things[l].score=300;
  406.       }
  407.     if(!loaded)
  408.       if(inloadcontact((pixx+shipdx+160)%lenx3,
  409.                (pixy+shipdy+88)%leny3)) {
  410.         loadcontact=1;
  411.         *(bana+lenx*loadby+loadbx)=32;
  412.         drawload(0);
  413.       }
  414.       }
  415.       else {
  416.     shield=0;
  417.     if(alive && loadcontact) {
  418.       *(bana+lenx*loadby+loadbx)=253;
  419.       drawload(1);
  420.       loadcontact=0;
  421.     }
  422.       }
  423.       if(alive && (actionbits&thrust_bit)) {
  424.     if(fuel>0) {
  425. #ifndef DEBUG
  426.       if(!easyrider)
  427.         fuel--;
  428. #endif
  429.       oldabs=speedx*(long)speedx+speedy*(long)speedy;
  430.       if(loaded) {
  431.         aradial=(SPEED*sinus2[((dir<<5)-alpha+256)&1023]) >> 8;
  432.         acircum=(SPEED*sinus2[((dir<<5)-alpha)&1023]) >> 9;
  433.         ax=(aradial*(SPEED*sinus2[(alpha+256)&1023] >> 8)) >> 10;
  434.         ay=(-aradial*(SPEED*sinus2[alpha] >> 8)) >> 10;
  435.         deltaalpha=deltaalpha+acircum;
  436.         deltaalpha=min(deltaalpha, 16384);
  437.         deltaalpha=max(deltaalpha, -16384);
  438.       }
  439.       else {
  440.         ax=SPEED*sinus[(dir+8)&31]>>9;
  441.         ay=-SPEED*sinus[dir]>>9;
  442.       }
  443.       speedx+=ax;
  444.       speedy+=ay;
  445.       absspeed=speedx*(long)speedx+speedy*(long)speedy;
  446.       if(absspeed>1000000000L && absspeed>oldabs) {
  447.         speedx-=ax;
  448.         speedy-=ay;
  449.       }
  450.     }
  451.       }
  452.       if(loaded) {
  453.     if(loadpointshift) {
  454.       speedx+=shipdx*12;
  455.       speedy+=shipdy*12;
  456.     }
  457.     alpha=(alpha+(deltaalpha>>9))&1023;
  458.     loadpointshift=0;
  459.     if(++loadpoint>126)
  460.       loadpoint=126;
  461.     else
  462.       loadpointshift=1;
  463.     shipdx=(sinus2[(alpha+256)&1023]*loadpoint)/1512;
  464.     shipdy=(-sinus2[alpha]*loadpoint)/1512;
  465.     if(loadpointshift) {
  466.       speedx-=shipdx*12;
  467.       speedy-=shipdy*12;
  468.     }
  469.     if(deltaalpha>0)
  470.       deltaalpha=deltaalpha-(deltaalpha>>10)-1;
  471.     else if(deltaalpha<0)
  472.       deltaalpha=deltaalpha-(deltaalpha>>10)+1;
  473.     if(abs(deltaalpha)<2)
  474.       deltaalpha=0;
  475.       }
  476.       else
  477.     shipdx=shipdy=0;
  478.       /* Gravity and Aerodynamics */
  479.       if(speedx>0)
  480.     speedx=speedx-(speedx>>9)-1;
  481.       else if(speedx<0)
  482.     speedx=speedx-(speedx>>9)+1;
  483.       if(alive) {
  484.     speedy+=SPEED*gravity>>8;
  485.     if(speedy>0)
  486.       speedy--;
  487.     else if(speedy<0)
  488.       speedy++;
  489.     /* Move the Ship */
  490.     speedx=min(speedx,16384);
  491.     speedx=max(speedx,-16384);
  492.     speedy=min(speedy,16384);
  493.     speedy=max(speedy,-16384);
  494.     vx=speedx>>8;
  495.     vy=speedy>>8;
  496.     x=(x+vx+(lenx<<6))%(lenx<<6);
  497.     y=(y+vy+(leny<<6))%(leny<<6);
  498.       }
  499.  
  500.       /* Bunkerfire */
  501.       bunkerfirebullets();
  502.       movebullets();
  503.       movefragments();
  504.       drawfuel(fuel);
  505.  
  506.       /* Move the Spacestationblip */
  507.       scount=(scount+1)&15;
  508.       if(!scount && spacestation && ssblip)
  509.     ssblip--;
  510.  
  511.       if(!spacestation) {
  512.     countdown--;
  513.     if(countdown<0) {
  514. #ifndef DEBUG
  515.       if(alive && !easyrider) {
  516.         dying=1;
  517.       }
  518. #endif
  519.     }
  520.     else {
  521.       chflag=1;
  522.       if(countdown&16)
  523.         chcolor=0;
  524.       else
  525.         chcolor=20;
  526.       sprintf(textstr,"%d  ",(countdown+99)/100);
  527.       printgs(155,180,textstr);
  528.       chcolor=20;
  529.       chflag=0;
  530.     }
  531.       }
  532.  
  533.       /* Precalculate some values */
  534.       pixx=x>>3;
  535.       pixy=y>>3;
  536.       bildx=(pixx+PBILDX-4)%PBILDX+4;
  537.       bildy=pixy%PBILDY;
  538.       pblockx=pixx>>3;
  539.       pblocky=pixy>>3;
  540.       bblockx=bildx>>3;
  541.       bblocky=bildy>>3;
  542.       if(wrapers)
  543.     if(pblocky>BBILDY && pblocky<2*BBILDY) {
  544.       y-=PBILDY<<3;
  545.       pixy-=PBILDY;
  546.       pblocky-=BBILDY;
  547.       unwrapbullets();
  548.       unwrapfragments();
  549.       wrapers--;
  550.     }
  551.       if(pblocky>leny-3) {
  552.     if(loaded) {
  553.       endlevel=1;
  554.       teleport=1;
  555.       if(!easyrider)
  556.         localscore+=4000+400*level-2000*spacestation;
  557.       if(++level==LEVELS) {
  558.         level=0;
  559.         round=(round+1)%4;
  560.       }
  561.     }
  562.     y+=(PBILDY-leny3)<<3;
  563.     pixy+=PBILDY-leny3;
  564.     pblocky+=BBILDY-leny;
  565.     wrapbullets();
  566.     wrapfragments();
  567.     if(!++wrapers)
  568.       wrapers--;
  569.       }
  570.  
  571.       /* Check if at a restart barrier. If so, update the restart point. */
  572.       restartxy=atbarrier((pblockx+((154+shipdx)>>3))%lenx,
  573.               pblocky+((82+shipdy)>>3));
  574.       if(restartxy) {
  575.     restartx=(restartxy->x-(154>>3))%lenx;
  576.     restarty=restartxy->y-(82>>3);
  577.       }
  578.  
  579.       /* Scroll the screen */
  580.       setmargin(253,1);
  581.       updateborder(pblockx,pblocky,bblockx,bblocky,vx,vy);
  582.       
  583.       drawspacestationblip();
  584.       setmargin(255,1);
  585.       drawbullets();
  586.       if(alive)
  587.     crash=drawshuttle();
  588.       drawfragments();
  589.       if(alive && refueling)
  590.     drawfuellines();
  591.       /* Check if end of life. */
  592. #ifndef DEBUG
  593.       if(!easyrider)
  594.     if(alive && crash) {
  595.       lives--;
  596.       dying=1;
  597.     }
  598. #endif
  599.       /* Wait for the screen retrace and then dump the graphics to it. */
  600.       setmargin(crash,1);
  601.       vga_waitretrace();
  602.       setmargin(crash,1);
  603.       
  604.       /* Screendump */
  605. /*    if(keyboard_keypressed(63)) *//* F5 */
  606. /*      savegraphics(bildx,bildy);*/
  607.       putscr(bildx,bildy);
  608.  
  609.       /* Remove moveable objects from screen in reverse order. */
  610.       if(alive && refueling)
  611.     undrawfuellines();
  612.       setmargin(120,1);
  613.       undrawfragments();
  614.       if(alive)
  615.     undrawshuttle();
  616.       undrawbullets();
  617.     
  618.       /* Remove objects */
  619.       if(!easyrider)
  620.     localscore+=killdyingthings();
  621.       else
  622.     killdyingthings();
  623.       if(dying) {
  624.     alive=0;
  625.     dying=0;
  626.     explodeship();
  627.       }
  628.       if(!alive && !livefragments())
  629.     endlevel=1;
  630.       animatesliders();
  631.       if(localscore>score) {
  632.     chflag=1;
  633.     if(localscore/10000 > score/10000) {
  634.       lives++;
  635.       sprintf(textstr,"LIVES: %d",lives);
  636.       printgs(20,192,textstr);
  637.     }
  638.     score=localscore;
  639.     sprintf(textstr,"SCORE: %d         ",score);
  640.     printgs(20,184,textstr);
  641.     chflag=0;    
  642.       }
  643.     }
  644.     if(teleport)
  645.       drawteleport();
  646.     teleport=0;
  647.  
  648.     if(!(actionbits&(quit_bit|escape_bit)))
  649.       usleep(1000000UL);
  650.     fade_out();
  651.  
  652.     if(demo)
  653.       level=LEVELS;
  654.   }
  655.  
  656.   return(0);
  657. }
  658.  
  659. void
  660. pressanykey()
  661. {
  662.   keyboard_close();
  663.   vga_unlockvc();
  664.  
  665.   do 
  666.     usleep(10000UL);
  667.   while(!vga_getkey());
  668.  
  669.   vga_lockvc();
  670.   keyboard_init();
  671. }
  672.  
  673. int
  674. instructions()
  675. {
  676.   int i;
  677.   static char *keys[] = {
  678.     "'A'", "'S'", "'ENTER'", "'R-CTRL'", "'SPACE'", "'ESC'", "'P'", "'C'" };
  679.   static char *func[] = {
  680.     "TURN LEFT", "TURN RIGHT", "FIRE", "THRUST",
  681.     "PICK UP AND SHIELD", "QUIT GAME (Q=ESC)", "PAUSE", "CONTINUE" };
  682.  
  683.   gcenter(50, "THE FOLLOWING KEYS ARE USED:");
  684.   for(i=0; i<8; i++) {
  685.     chcolor++;
  686.     printgs(140-gstrlen(keys[i]), 63+i*8+2*(i>4), keys[i]);
  687.     chcolor--;
  688.     printgs(145, 63+i*8+2*(i>4), func[i]);
  689.   }
  690.   gcenter(150, "PRESS ANY KEY FOR MAIN MENU.");
  691.  
  692.   fade_in();
  693.   pressanykey();
  694.   fade_out();
  695.  
  696.   return(0);
  697. }
  698.  
  699. int
  700. about()
  701. {
  702.   int i;
  703.   char *str[] = {
  704.     "THRUST VERSION " VERSION,
  705.     "",
  706.     "WRITTEN BY",
  707.     "",
  708.     "PETER EKBERG",
  709.     "PEDA@LYSATOR.LIU.SE",
  710.     "",
  711.     "THANKS TO THE AUTHORS",
  712.     "OF THE ORIGINAL",
  713.     "FOR THE C64.",
  714.     NULL
  715.   };
  716.  
  717.   for(i=0; str[i]; i++)
  718.     gcenter(40+9*i, str[i]);
  719.   gcenter(145, "PRESS ANY KEY FOR MAIN MENU.");
  720.  
  721.   fade_in();
  722.   pressanykey();
  723.   fade_out();
  724.  
  725.   return(0);
  726. }
  727.  
  728. char *
  729. enterhighscorename()
  730. {
  731.   static char name[40];
  732.   char str[40];
  733.   
  734.   strcpy(name, standardname());
  735.   sprintf(str, "YOU MANAGED %d POINTS!", score);
  736.   gcenter(64, str);
  737.   gcenter(75, "YOU MADE IT INTO THE HIGHSCORE LIST!");
  738.   gcenter(86, "ENTER YOUR NAME:");
  739.   printgs(130,97,name);
  740.   fade_in();
  741.  
  742.   keyboard_close();
  743.   vga_unlockvc();
  744.  
  745.   if(readgs(130, 97, name, 39, 80, 0)==-1)
  746.     strcpy(name, standardname());
  747.  
  748.   vga_lockvc();
  749.   keyboard_init();
  750.  
  751.   fade_out();
  752.  
  753.   return(name);
  754. }
  755.  
  756. int
  757. showhighscores()
  758. {
  759.   char str[100];
  760.   byte tmp=chcolor;
  761.   int i;
  762.   int scorew, namew;
  763.   int len;
  764.  
  765.   gcenter(50, "THE CURRENT HIGHSCORES ARE");
  766.  
  767.   scorew=namew=0;
  768.   for(i=0; i<HIGHSCORES; i++) {
  769.     sprintf(str, "%d", highscorelist[i].score);
  770.     len=gstrlen(str);
  771.     if(len>scorew)
  772.       scorew=len;
  773.     len=gstrlen(highscorelist[i].name);
  774.     if(len>namew)
  775.       namew=len;
  776.   }
  777.  
  778.   for(i=0; i<HIGHSCORES; i++) {
  779.     sprintf(str, "%d", highscorelist[i].score);
  780.     chcolor=12;
  781.     printgs(155+(scorew-namew)/2-gstrlen(str), 70+11*i, str);
  782.     chcolor=13;
  783.     printgs(165+(scorew-namew)/2, 70+11*i, highscorelist[i].name);
  784.   }
  785.  
  786.   chcolor=tmp;
  787.   gcenter(145, "PRESS ANY KEY FOR MAIN MENU.");
  788.  
  789.   fade_in();
  790.   pressanykey();
  791.   fade_out();
  792.  
  793.   return(0);
  794. }
  795.  
  796. void
  797. newhighscore()
  798. {
  799.   char *name;
  800.  
  801.   name = enterhighscorename();
  802.   inserthighscore(name, score);
  803.   writehighscores();
  804.   showhighscores();
  805. }
  806.  
  807. options
  808. menu()
  809. {
  810.   int i,j;
  811.   options end=NOTHING;
  812.   int ch;
  813.   static char *menuchoises[NOTHING]= { "I", "H", "P", "A", "Q" };
  814.   static char *menuoptions[NOTHING]= {
  815.     "INSTRUCTIONS", "HIGHSCORES", "PLAY GAME", "ABOUT", "QUIT" };
  816.   int count=0;
  817.  
  818.   for(i=0; i<150; i++)
  819.     for(j=0; j<300; j++)
  820.       *(graph_mem+(i+15)*320+j+10)=intro[i*300+j]+192;
  821.   for(i=0; i<NOTHING; i++) {
  822.     chcolor--;
  823.     gcenter(130+i*11,menuoptions[i]);
  824.     chcolor++;
  825.     printgs(160-(gstrlen(menuoptions[i])>>1), 130+i*11, menuchoises[i]);
  826.   }
  827.  
  828.   fade_in();
  829.   keyboard_close();
  830.   vga_unlockvc();
  831.  
  832.   while(end==NOTHING) {
  833.     ch=vga_getkey();
  834.     switch(tolower(ch)) {
  835.     case 'i':
  836.       end=INST;
  837.       break;
  838.     case 'p':
  839.       end=PLAY;
  840.       break;
  841.     case 'h':
  842.       end=HI;
  843.       break;
  844.     case 'a':
  845.       end=ABOUT;
  846.       break;
  847.     case 'd':
  848.       end=DEMO;
  849.       break;
  850.     case 'q':
  851.     case 27:
  852.       end=END;
  853.       break;
  854.     default:
  855.       break;
  856.     }
  857.     usleep(10000UL);
  858.  
  859.     /* You may want to comment the following statement out if you don't
  860.        want your box to keep running the demo every once in a while. */
  861.     if(++count==800)
  862.       end=DEMO;
  863.   }
  864.  
  865.   vga_lockvc();
  866.   keyboard_init();
  867.   fade_out();
  868.  
  869.   return(end);
  870. }
  871.  
  872. int
  873. main(int argc, char *argv[])
  874. {
  875.   int end=0;
  876.   uid_t uid;
  877.  
  878.   /* Keep root priviliges for highscore file.
  879.      If you have security concerns and do not
  880.      care about the highscore file, remove the
  881.      setreuid() and getuid() calls surrounding
  882.      the call to inithardware() */
  883.   uid=getuid();
  884.   setreuid(0,-1);
  885.   inithardware();
  886.   setreuid(uid, -1);
  887.  
  888.   if(!initmem()) {
  889.     restorehardware();
  890.     return(1);
  891.   }
  892.   inithighscorelist();
  893.  
  894.   sleep(1);
  895.  
  896.   while(!end) {
  897.     switch(menu()) {
  898.     case INST:
  899.       instructions();
  900.       break;
  901.     case PLAY:
  902.       if(!(end=game(0)))
  903.     if(ahighscore(score))
  904.       newhighscore();
  905.       break;
  906.     case HI:
  907.       showhighscores();
  908.       break;
  909.     case ABOUT:
  910.       about();
  911.       break;
  912.     case DEMO:
  913.       game(1);
  914.       break;
  915.     case END:
  916.       end=1;
  917.       break;
  918.     default:
  919.       break;
  920.     }
  921.   }
  922.  
  923.   restoremem();
  924.   restorehardware();
  925.   
  926.   return(0);
  927. }
  928.